/* Copyright (c) 2008 Google Inc.
*  Copyright (c) 2009 Pierre Henri Kuate.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

using System;
using System.Net;
using System.IO;
namespace org.opensocial.client
{
    /// <summary> An internal object which represents a single HTTP request and contains a
    /// minimal set of methods for setting request properties, submitting the
    /// request, and retrieving the response which can later be parsed into a
    /// more meaningful object.
    /// </summary>
    /// <author>  Jason Cooper
    /// </author>
    public class OpenSocialHttpRequest
    {
        private HttpWebRequest connection;
        private readonly OpenSocialUrl url;

        public OpenSocialHttpRequest(string requestMethod, OpenSocialUrl requestUrl)
        {
            Method = requestMethod;
            url = requestUrl;
        }

        public string Method
        {
            get; set;
        }

        public string ContentType
        {
            get; set;
        }

        public string Body
        {
            get; set;
        }

        /// <summary> Opens a new HTTP connection for the URL associated with this object.
        /// 
        /// </summary>
        /// <returns> Opened connection
        /// </returns>
        /// <throws>  IOException if URL protocol is not http </throws>
        private HttpWebRequest GetConnection()
        {
            var uri = new Uri(url.ToString());

            if (!uri.Scheme.StartsWith("http"))
                throw new System.IO.IOException("Unsupported scheme:" + uri.Scheme);

            return ((HttpWebRequest) WebRequest.Create(uri));
        }

        public string execute()
        {
            return execute(null);
        }

        /// <summary> Initializes connection if necessary before establishing the connection,
        /// including writing POST data to the connection's output stream if
        /// applicable.
        /// </summary>
        /// <returns> After executing the request, transforms response output contained in the
        /// connection's InputStream object into a string representation which can
        /// later be parsed into a more meaningful object, e.g. OpenSocialObject.
        /// </returns>
        /// <throws>  IOException </throws>
        public string execute(string rpc_method)
        {
            if (string.IsNullOrEmpty(Method) || string.IsNullOrEmpty(ContentType))
                throw new OpenSocialException("Not properly initialized");

            if (connection == null)
            {
                connection = GetConnection();
            }

            connection.Method = Method;
            connection.ContentType = ContentType;

            if (!string.IsNullOrEmpty(Body))
            {
                if (null != rpc_method && rpc_method.CompareTo("mediaitems.upload") == 0)
                {
                    byte[] bytes = Convert.FromBase64String(Body);
                    connection.ContentLength = bytes.Length;
                    connection.GetRequestStream().Write(bytes, 0, bytes.Length);
                }
                else
                {
                    using (var wr = new System.IO.StreamWriter(connection.GetRequestStream()))
                    {
                        wr.Write(Body);
                        wr.Flush();
                    }
                }
            }

            using (var response = (HttpWebResponse)connection.GetResponse())
            {
                if (response.StatusCode == HttpStatusCode.OK || response.StatusCode == HttpStatusCode.Created)
                    using (var responseStream = new System.IO.StreamReader(response.GetResponseStream()))
                        return responseStream.ReadToEnd();
                throw new OpenSocialRequestException("Request returned error code: " + response.StatusCode);
            }
        }

        /// <summary> Returns instance variable: url.</summary>
        public OpenSocialUrl getUrl()
        {
            return url;
        }
    }
}